package com.game.service.oss;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.game.common.constant.Constant;
import com.game.entity.SysFilesEntity;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 阿里云上传文件
 *
 * @author 不愿透露
 * @date 2022/6/29 16:40
 */
@Service
@Slf4j
public class AliyunOssservice {


    private SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

    /**
     * 处理文件类型,用于文件存储时设置对应存储类型和访问权限
     *
     * @param FilenameExtension
     * @return
     */
    public static String getcontentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".pdf")) {
            return "application/pdf";
        }
        if (FilenameExtension.equalsIgnoreCase(".zip")) {
            return "application/zip";
        }
        if (FilenameExtension.equalsIgnoreCase(".xls") ||
                FilenameExtension.equalsIgnoreCase(".xlsx")) {
            return "application/vnd.ms-excel";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "application/octet-stream";
    }

    /**
     * 阿里云上传文件
     *
     * @param file
     * @return java.lang.String
     * @author 不愿透露
     * @date 2022/6/29 16:39
     */
    public SysFilesEntity upload(MultipartFile file, String pathType) {
        //meiguosgo
        String bucketName = Constant.configs.get("aliyun_bucket_name");
        //oss-us-west-1.aliyuncs.com
        String endpoint = Constant.configs.get("aliyun_end_point");
        //LTAI5tDiDdG3DvT8XBYU8JgQ
        String accessKeyId = Constant.configs.get("aliyun_access_key_id");
        //EaDIppDREQz5PxfZAI5HlSi8BJ0ihm
        String accessKeySecret = Constant.configs.get("aliyun_access_key_secret");
        //上传到阿里云的位置和项目名称，默认从bucket开始。
        //    String objectName="文件/test01";
        //本地被上传文件的地址，要求为绝对路路径
        // String filePath="D:\\Game\\test.txt";
        //创建OSSClient实例
        String dateStr = sdf.format(new Date());
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            //容器不存在，就创建,权限为私有的
            if (!ossClient.doesBucketExist(bucketName)) {
                ossClient.createBucket(bucketName);
                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
                createBucketRequest.setCannedACL(CannedAccessControlList.Private);
                ossClient.createBucket(createBucketRequest);
            }
            //上传时设置存储类型和访问权限
            String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
            String fileName = UUID.randomUUID().toString().replace("-", "") + suffix;
            //创建文件路径
            String filePath = (Constant.configs.get("aliyun_file")+"/"+pathType + "/" + dateStr + "/" + fileName);

            //上传文件,附带有桶、文件地址、文件、文件存储属性，
            PutObjectResult result = null;
            if (isImg(suffix)) {
                byte[] bytes = compressPicForScale(file.getBytes());
                ObjectMetadata objectMetadata = new ObjectMetadata();
                objectMetadata.setContentLength(bytes.length);
                objectMetadata.setContentType(file.getContentType());
                InputStream sbs = new ByteArrayInputStream(bytes);
                PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, filePath, sbs, objectMetadata);
                result = ossClient.putObject(putObjectRequest);
            }
            if (result == null) {
                result = ossClient.putObject(bucketName, filePath, file.getInputStream());
            }
            if (result != null) {
                String fileUrl = "https://" + bucketName + "." + endpoint + "/" + filePath;
                SysFilesEntity sysFilesEntity = new SysFilesEntity();
                sysFilesEntity.setFileName(fileName);
                sysFilesEntity.setFilePath(filePath);
                sysFilesEntity.setUrl(fileUrl);
                sysFilesEntity.setCreateDate(new Date());
                return sysFilesEntity;
            }
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return null;
    }

    public static boolean isImg(String name) {
        Pattern pattern = Pattern.compile(".+(bmp|jpg|png|tif|gif|pcx|tga|exif|fpx|svg|psd|cdr|pcd|dxf|ufo|eps|ai|raw|WMF|webp|jpeg)$");
        return pattern.matcher(name).matches();
    }

    /**
     * 图片压缩
     *
     * @param imageBytes
     * @return byte[]
     * @author 不愿透露
     * @date 2022/8/11 22:15
     */
    public static byte[] compressPicForScale(byte[] imageBytes) {
        if (imageBytes == null || imageBytes.length <= 0) {
            return imageBytes;
        }
        try {
            ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
            Thumbnails.of(inputStream)
                    .scale(1D)
                    .outputQuality(0.5)
                    .toOutputStream(outputStream);
            imageBytes = outputStream.toByteArray();
        } catch (Exception e) {

        }
        return imageBytes;
    }

    //从bucket中根据url删除指定文件
    //参数就一个被删除文件的地址
    public void delFile(String filePath) {
        //meiguosgo
        String bucketName = Constant.configs.get("aliyun_bucket_name");
        //oss-us-west-1.aliyuncs.com
        String endpoint = Constant.configs.get("aliyun_end_point");
        //LTAI5tDiDdG3DvT8XBYU8JgQ
        String accessKeyId = Constant.configs.get("aliyun_access_key_id");
        //EaDIppDREQz5PxfZAI5HlSi8BJ0ihm
        String accessKeySecret = Constant.configs.get("aliyun_access_key_secret");
        // 填写文件完整路径。文件完整路径中不能包含Bucket名称。
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 删除Object.
        boolean exist = ossClient.doesObjectExist(bucketName, filePath);
        if (!exist) {
            return;
        }
        ossClient.deleteObject(bucketName, filePath);
        ossClient.shutdown();
    }

    public List<String> fileFolder(String fileName) {
        String bucketName = Constant.configs.get("aliyun_bucket_name");
        //oss-us-west-1.aliyuncs.com
        String endpoint = Constant.configs.get("aliyun_end_point");
        //LTAI5tDiDdG3DvT8XBYU8JgQ
        String accessKeyId = Constant.configs.get("aliyun_access_key_id");
        //EaDIppDREQz5PxfZAI5HlSi8BJ0ihm
        String accessKeySecret = Constant.configs.get("aliyun_access_key_secret");
        // 填写文件完整路径。文件完整路径中不能包含Bucket名称。
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 构造ListObjectsRequest请求。
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);

        // 设置正斜线（/）为文件夹的分隔符。
        listObjectsRequest.setDelimiter("/");
        // 设置prefix参数来获取fun目录下的所有文件。
        if (!StringUtils.isEmpty(fileName)) {
            listObjectsRequest.setPrefix(fileName + "/");
        }
        // 列出文件
        ObjectListing listing = ossClient.listObjects(listObjectsRequest);
        // 遍历所有commonPrefix
        List<String> list = new ArrayList<>();
        for (String commonPrefix : listing.getCommonPrefixes()) {
            String newCommonPrefix = commonPrefix.substring(0, commonPrefix.length() - 1);
            String[] s = newCommonPrefix.split("/");
            if (!StringUtils.isEmpty(fileName)) {
                list.add(s[s.length - 1]);
            } else {
                list.add(s[0]);
            }
        }
        // 关闭OSSClient
        ossClient.shutdown();
        return list;
    }

    public List<SysFilesEntity> listFile(String fileHost, String nextMarker) {
        String bucketName = Constant.configs.get("aliyun_bucket_name");
        //oss-us-west-1.aliyuncs.com
        String endpoint = Constant.configs.get("aliyun_end_point");
        //LTAI5tDiDdG3DvT8XBYU8JgQ
        String accessKeyId = Constant.configs.get("aliyun_access_key_id");
        //EaDIppDREQz5PxfZAI5HlSi8BJ0ihm
        String accessKeySecret = Constant.configs.get("aliyun_access_key_secret");
        // 填写文件完整路径。文件完整路径中不能包含Bucket名称。
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 构造ListObjectsRequest请求
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);

        // 设置prefix参数来获取fun目录下的所有文件。
        listObjectsRequest.setPrefix(fileHost + "/");
        listObjectsRequest.setMarker(nextMarker);
        listObjectsRequest.withMaxKeys(1000);


        // 列出文件。
        ObjectListing listing = ossClient.listObjects(listObjectsRequest);

        // 遍历所有文件。
        List<SysFilesEntity> list = new ArrayList<>();
        for (int i = 0; i < listing.getObjectSummaries().size(); i++) {
            String filePath = listing.getObjectSummaries().get(i).getKey();
            if (filePath.indexOf(".") > -1) {
                String FILE_URL = "https://" + bucketName + "." + endpoint + "/" + filePath;
                SysFilesEntity sysFilesEntity = new SysFilesEntity();
                sysFilesEntity.setUrl(FILE_URL);
                sysFilesEntity.setFilePath(filePath);
                list.add(sysFilesEntity);
            }
        }
        // 关闭OSSClient。
        ossClient.shutdown();


//        ObjectListing objectListing = null;
//        int total = 0;
//        HashMap<Integer, String> markerMap = new HashMap<>();
//        try {
//            ObjectListing objectListing2 = null;
//            do {
//                String nextMarker2 = objectListing2 != null ? objectListing2.getNextMarker() : null;
//                ListObjectsRequest listObjectsRequest2 = new ListObjectsRequest(bucketName).withMarker(nextMarker2).withMaxKeys(100);
//                listObjectsRequest2.setPrefix(fileHost + "/");
//                objectListing2 = ossClient.listObjects(listObjectsRequest2);
//                total += (objectListing2 != null && objectListing2.getObjectSummaries() != null ? objectListing2.getObjectSummaries().size() : 0);
//                markerMap.put(markerMap.size() + 1, nextMarker2);
//            } while (objectListing2 != null && !StringUtils.isEmpty(objectListing2.getNextMarker()));
//
//            ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName).withMarker(nextMarker).withMaxKeys(100);
//
//            listObjectsRequest.setPrefix(fileHost + "/");
//
//            objectListing = ossClient.listObjects(listObjectsRequest);
//            for (int i = 0; i < objectListing.getObjectSummaries().size(); i++) {
//                String FILE_URL = "https://" + bucketName + "." + endpoint + "/" + objectListing.getObjectSummaries().get(i).getKey();
//                list.add(FILE_URL);
//            }
//
//        } catch (Exception e) {
//
//        } finally {
//            // 关闭client
//            ossClient.shutdown();
//        }

        return list;
    }

    /*//从bucket中下载文件到本地，有文件直接下载、流式下载、断点下载
    //参考文档代码 https://help.aliyun.com/document_detail/84824.html
    //1、参数一：objectName:文件在bucket中的位置
    //2、参数二：pathName:下载到本地的保存路径
    public void exportOssFile() {
        String endpoint = ossConstantProperties.getEndPoint();
        String accessKeyId = ossConstantProperties.getAccessKeyId();
        String accessKeySecret = ossConstantProperties.getAccessKeySecret();
        String bucketName = ossConstantProperties.getBucketName();
        // 填写不包含Bucket名称在内的Object完整路径，例如testfolder/exampleobject.txt。
        //这里需要考虑一下文件路径加名称问题
        String objectName = "文件/计算机系统实践.doc";
        String pathName = "E:\\小组学习\\测试下载\\计算机系统实践.doc";
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            // 下载Object到本地文件，并保存到指定的本地路径中。如果指定的本地文件存在会覆盖，不存在则新建。
            // 如果未指定本地路径，则下载后的文件默认保存到示例程序所属项目对应本地路径中。
            ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(pathName));
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    */
}

